﻿(function() {
	function CreateWind(options){
		//this.speedupThresHold = 0; //风速阀值,低于该风速的不显示
		//this.OVERLAY_ALPHA = Math.floor(0.7 * 255); //覆盖层的透明度 (on scale [0, 255])
		this.options = options;
		this.header = {};
		this.mapAgent = new tools.newAgent();
		this.gridAgent = new tools.newAgent();
		this.fieldAgent = new tools.newAgent();
		this.animatorAgent = new tools.newAgent();
		this.overlayAgent = new tools.newAgent();
	}
	CreateWind.prototype = {
		getGridAgent:function(){
			return this.gridAgent;
		},
		getFieldAgent:function(){
			return this.fieldAgent;
		},
		getAnimatorAgent:function(){
			return this.animatorAgent;
		},
		getOverlayAgent:function(){
			return this.overlayAgent;
		},
		initialize:function(){
			this.speedupThresHold = 0; //风速阀值,低于该风速的不显示
			this.OVERLAY_ALPHA = Math.floor(0.7 * 255); //覆盖层的透明度 (on scale [0, 255])
			this.fieldAgent.listenTo(this.gridAgent, 'update', this.startInterpolation);
			this.animatorAgent.listenTo(this.fieldAgent, 'update', this.animate);
			this.overlayAgent.listenTo(this.fieldAgent, "update", this.drawOverLay);
			this.gridAgent.submit(this.buildGrids, this.options);
		},
		startInterpolation:function(grids){
			this.submit(interpolateField, grids);
		},
		animate:function(field){
			//这句注释掉就没有风的动画
			this.submit(animate, field, windObj.getGridAgent().value());
		},
		drawOverLay:function(field) {
			//这句注释掉没有风速
			this.submit(drawOverlay, field, windObj.getGridAgent(), windObj.options);
		},
		draw:function(){
			/**
			this.fieldAgent.submit(interpolateField, windObj.getGridAgent());
			this.animatorAgent.submit(animate, windObj.getFieldAgent(), windObj.getGridAgent().value());
			this.overlayAgent.submit(drawOverlay, windObj.getFieldAgent(), windObj.getGridAgent(), windObj.options);
			**/
			//this.gridAgent.submit(this.buildGrids, this.options);
			this.fieldAgent.submit(interpolateField, windObj.getGridAgent().value());
			//this.overlayAgent.submit(drawOverlay,windObj.getFieldAgent().value(), windObj.getGridAgent(), windObj.options);
			//this.animatorAgent.submit(animate, windObj.getFieldAgent().value(), windObj.getGridAgent().value());
		},
		zoom:function(width, height){
			//windObj.bounds.width = width;
			//windObj.bounds.height = height;
			windObj.bounds.xMax = width;
			windObj.bounds.yMax = height;
			d3.select('#display').style('width',width + 'px').style('height', height + 'px');
			d3.select('#overlay').attr('width', width).attr('height', height);
			d3.select('#animation').attr('width', width).attr('height', height);
		},
		moveTo:function(spixelx,spixely,epixelx,epixely){
			d3.select('#display').style('left',spixelx + 'px').style('top',spixely + 'px');
			if(spixelx<0){
				//超过左边界
				console.log('←');
			}
			if(spixely<0){
				//超过上边界
				console.log('↑');
			}
			if(epixelx>document.body.clientWidth){
				//超过右边界
				console.log('→');
			}
			if(epixely>document.body.clientHeight){
				//超过下边界
				console.log('↓');
			}
		},
		remove:function(){
			
		},
		destory:function(){
			
		},
		setSpeedupThresHold:function(speedupThresHold){
			this.speedupThresHold = speedupThresHold;
		},
		buildGrids:function(options) {
			var cancel = this.cancel;
			var loaded = when.map(products.productsFor(options), function(product) {
				//这句开始加载数据
				return product.load(cancel);
			});
			return when.all(loaded).then(function(products) {
				return {
					primaryGrid : products[0],
					overlayGrid : products[1] || products[0],
					options : options
				};
			});
		}
	}	
	
	var τ = 2 * Math.PI; //常量
	var H = 0.0000360; // 0.0000360°φ ~= 4m
	var TRANSPARENT_BLACK = [ 0, 0, 0, 0 ]; // singleton 0 rgba
	var HOLE_VECTOR = [ NaN, NaN, null ]; //表示向量字段的一个孔
	var INTENSITY_SCALE_STEP = 1.6; //一步粒子大小的色阶强度
	var PARTICLE_MULTIPLIER = 1.3; // particle count scalar (completely arbitrary--this values looks nice) 粒子计数标量
	var MAX_PARTICLE_AGE = 50; // max number of frames a particle is drawn before regeneration
	var FRAME_RATE = 200; // desired milliseconds per frame
	var NULL_WIND_VECTOR = [ NaN, NaN, null ]; // singleton for undefined location outside the vector field [u, v, mag]
	var PARTICLE_LINE_WIDTH = 1.0; // line width of a drawn particle
	var MAX_TASK_TIME = 100;
	var MIN_SLEEP_TIME = 25;

	/**
	var center = 128;
	var width = 127;
	var redFrequency = 0.07;
	var grnFrequency = 0.07;
	var bluFrequency = 0.07;
	var phase1 = 0;
	var phase2 = 2;
	var phase3 = 2.7;
	**/

	var topSpeed = 13;
	var maxSpeed = 12;
	var minSpeed = 0;
	var bottomSpeed = 0;

	function bilinearInterpolateVector(x, y, g00, g10, g01, g11) {
		var rx = (1 - x);
		var ry = (1 - y);
		var a = rx * ry, b = x * ry, c = rx * y, d = x * y;
		var u = g00[0] * a + g10[0] * b + g01[0] * c + g11[0] * d;
		var v = g00[1] * a + g10[1] * b + g01[1] * c + g11[1] * d;
		return [ u, v, Math.sqrt(u * u + v * v) ];
	}
	function floorMod(a, n) {
		var f = a - n * Math.floor(a / n);
		// HACK: when a is extremely close to an n transition, f can be equal to n. This is bad because f must be
		//       within range [0, n). Check for this corner case. Example: a:=-1e-16, n:=10. What is the proper fix?
		return f === n ? 0 : f;
	}
	function isValue(x) {
		return x !== null && x !== undefined;
	}
	var BOUNDARY = 1; //修改这个值会影响生成风速图层的颜色
	var fadeToWhite = colorInterpolator(sinebowColor(1.0, 0), [ 255, 255, 255 ]);
	function extendedSinebowColor(i, a) {
		return i <= BOUNDARY ? sinebowColor(i / BOUNDARY, a) : fadeToWhite(
				(i - BOUNDARY) / (1 - BOUNDARY), a);
	}
	/**
	 * Produces a color style in a rainbow-like trefoil color space. Not quite HSV, but produces a nice
	 * spectrum. See http://krazydad.com/tutorials/makecolors.php.
	 *
	 * @param hue the hue rotation in the range [0, 1]
	 * @param a the alpha value in the range [0, 255]
	 * @returns {Array} [r, g, b, a]
	 */
	function sinebowColor(hue, a) {
		// Map hue [0, 1] to radians [0, 5/6τ]. Don't allow a full rotation because that keeps hue == 0 and
		// hue == 1 from mapping to the same color.
		var rad = hue * τ * 11 / 12;
		rad *= 0.75; // increase frequency to 2/3 cycle per rad

		var s = Math.sin(rad);
		var c = Math.cos(rad);
		var r = Math.floor(Math.max(0, -c) * 255);
		var g = Math.floor(Math.max(s, 0) * 255);
		var b = Math.floor(Math.max(c, 0, -s) * 255);
		return [ r, g, b, a ];
	}
	function colorInterpolator(start, end) {
		var r = start[0];
		var g = start[1];
		var b = start[2];
		var Δr = end[0] - r;
		var Δg = end[1] - g;
		var Δb = end[2] - b;
		return function(i, a) {
			return [ Math.floor(r + i * Δr), Math.floor(g + i * Δg),
					Math.floor(b + i * Δb), a ];
		};
	}
	/**
	 *计算失真的风矢量引起的投影点 (x，y) 的形状。风矢量是就地修改，该函数返回的。
	 *
	 */
	function distort(projection, λ, φ, x, y, scale, wind) {
		var u = wind[0] * scale;
		var v = wind[1] * scale;
		var d = distortion(projection, λ, φ, x, y);

		// Scale distortion vectors by u and v, then add.
		wind[0] = d[0] * u + d[2] * v;
		wind[1] = d[1] * u + d[3] * v;
		return wind;
	}
	function distortion(projection, λ, φ, x, y) {
		var hλ = λ < 0 ? H : -H;
		var hφ = φ < 0 ? H : -H;
		var pλ = projection([ λ + hλ, φ ]);
		var pφ = projection([ λ, φ + hφ ]);

		// Meridian scale factor (see Snyder, equation 4-3), where R = 1. This handles issue where length of 1° λ
		// changes depending on φ. Without this, there is a pinching effect at the poles.
		var k = Math.cos(φ / 360 * τ);

		return [ (pλ[0] - x) / hλ / k, (pλ[1] - y) / hλ / k, (pφ[0] - x) / hφ,
				(pφ[1] - y) / hφ ];
	}
	function asColorStyle(r, g, b, a) {
		return "rgba(" + r + ", " + g + ", " + b + ", " + a + ")";
	}

	/**
	 * @returns {Array} of wind colors and a method, indexFor, that maps wind magnitude to an index on the color scale.
	 */
	function windIntensityColorScale(step, maxWind) {
		var result = [];
		for (var j = 30; j <= 50; j += step) {
			j = parseInt(j);
			result.push(asColorStyle(j, j, j, 0.5));
		}
		result.indexFor = function(m) { // map wind speed to a style
			return Math.floor(Math.min(m, maxWind) / maxWind
					* (result.length - 1));
		};
		return result;
	}
	function clearCanvas(canvas) {
		canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height);
		return canvas;
	}
	function createField(columns, bounds, mask) {

		/**
		 * @returns {Array} wind vector [u, v, magnitude] at the point (x, y), or [NaN, NaN, null] if wind
		 *          is undefined at that point.
		 */
		function field(x, y) {
			var column = columns[Math.round(x)];
			return column && column[Math.round(y)] || NULL_WIND_VECTOR;
		}

		/**
		 * @returns {boolean} true if the field is valid at the point (x, y)
		 */
		field.isDefined = function(x, y) {
			return field(x, y)[2] !== null;
		};

		/**
		 * @returns {boolean} true if the point (x, y) lies inside the outer boundary of the vector field, even if
		 *          the vector field has a hole (is undefined) at that point, such as at an island in a field of
		 *          ocean currents.
		 */
		field.isInsideBoundary = function(x, y) {
			return field(x, y) !== NULL_WIND_VECTOR;
		};

		// Frees the massive "columns" array for GC. Without this, the array is leaked (in Chrome) each time a new
		// field is interpolated because the field closure's context is leaked, for reasons that defy explanation.
		field.release = function() {
			columns = [];
		};

		field.randomize = function(o) { // UNDONE: this method is terrible
			var x, y;
			var safetyNet = 0;
			do {
				x = Math.round(_.random(bounds.x, bounds.xMax));
				y = Math.round(_.random(bounds.y, bounds.yMax));
			} while (!field.isDefined(x, y) && safetyNet++ < 30);
			o.x = x;
			o.y = y;
			return o;
		};

		field.overlay = mask.imageData;

		return field;
	}
	/**
	 * Returns a human readable string for the provided scalar in the given units.
	 */
	function formatScalar(value, units) {
		return units.conversion(value).toFixed(units.precision);
	}
	/**
	 * @returns {number} the value p within the range [0, 1], scaled to the range [low, high].
	 */
	function spread(p, low, high) {
		return p * (high - low) + low;
	}
	/**
	 * @returns {Number} the value x clamped to the range [low, high].
	 */
	function clamp(x, low, high) {
		return Math.max(low, Math.min(x, high));
	}
	/**
	 * 核心算法，计算地图上所有的风速点。和画布的宽度width和高度height(像素)，横向有多少个风速点，纵向有多少个风速点，每两个点之间的间距有关
	 * 宽度734*501 个风速点  每个点之间是15m，算画布是734*501，每个像素点，表示一个风速点
	 */
	function buildGrid(builder) {
		var header = builder.header;
		var λ0 = header.width; //宽度
		var φ0 = header.height; //高度
		var Δλ = header.dx; //1
		var Δφ = header.dy; //1 网格点之间的距离
		var width = header.width; //734
		var height = header.height; //501
		var date = new Date(header.refTime);
		var grid = [], p = 0;
		for (var j = 0; j < height; j++) {
			var row = [];
			for (var i = 0; i < width; i++, p++) {
				row[i] = builder.data(p);
			}
			grid[j] = row;
		}
		function interpolate(x, y) {
			var x = parseInt(x/windObj.bounds.xMax*windObj.bounds.width);
			var y = parseInt(y/windObj.bounds.yMax*windObj.bounds.height);
			return grid[y][x];
		}
		return {
			date : date,
			interpolate : interpolate
		};

	}
	var products = function() {
		function buildProduct(overrides) {
			return _.extend({
				paths : [],
				load : function() {
					var me = this;
					return when.map(this.paths, tools.loadJson).then(
							function(files) {
								return _.extend(me, buildGrid(me.builder.apply(
										me, files)));
							});
				}
			}, overrides);
		}
		var factory = {
			create : function(attr) {
				return buildProduct({
					field : 'vector',
					type : 'wind',
					paths : attr.paths,
					animation : attr.renderTo[0],
					overlay : attr.renderTo[1],
					disp : attr.renderTo[3],
					builder : function(windDataJson) {
						var header = windDataJson.header;
						var direction = windDataJson.data.direction;
						var speedup = windDataJson.data.speedup;
						var vData = [], uData = [];
						for (var i = 0; i < speedup.length; i++) {
							//Ux=-u*cos((90.0-d)/180*PI)
							//Uy=u*sin((90.0-d)/180*PI)
							//Uz=u*tan(a)
							uData[i] = -speedup[i]
									* Math.cos((90.0 - direction[i]) / 180
											* Math.PI);
							vData[i] = speedup[i]
									* Math.sin((90.0 - direction[i]) / 180
											* Math.PI);
						}
						windObj.header = header;
						windObj.bounds = {
							height : header.height,
							width : header.width,
							x : header.x1,
							xMax : header.x2,
							y : header.y1,
							yMax : header.y2
						};
						var slng = windObj.header.slng;
						var slat = windObj.header.slat;
						var elng = windObj.header.elng;
						var elat = windObj.header.elat;
						
						var spixel = mapObj.lnglatTocontainer(new AMap.LngLat(slng, slat));
						var spixelX = spixel.getX();
						var spixelY = spixel.getY();
						
						var epixel = mapObj.lnglatTocontainer(new AMap.LngLat(elng, elat));
						var epixelX = epixel.getX();
						var epixelY = epixel.getY();
						
						var width = parseInt(epixelX - spixelX);
						var height = parseInt(epixelY - spixelY);
						windObj.zoom(width,height);
						windObj.moveTo(spixelX, spixelY);
						//var vData = windDataJson.data.uy;
						//var uData = windDataJson.data.ux;
						return {
							header : header,
							interpolate : bilinearInterpolateVector,
							data : function(i) {
								return [ uData[i], vData[i], speedup[i] ]; //添加一个风速
							}
						};
					},
					units : [ {
						label : "m/s",
						conversion : function(x) {
							return x;
						},
						precision : 1
					} ],
					scale : {
						bounds : [ 0, 12 ], //修改不会影响风速图
						gradient : function(v, a) {
							return extendedSinebowColor(Math.min(v, 12) / 12, a); //修改会影响风速图
						},
						makeColorByWindSpeedUp : function(frequency1,
								frequency2, frequency3, phase1, phase2, phase3,
								center, width, speedup, a) {
							if (center == undefined)
								center = 128;
							if (width == undefined)
								width = 127;
							if (speedup == undefined)
								return;
							var red = Math.sin(frequency1 * speedup + phase1)
									* width + center;
							var grn = Math.sin(frequency2 * speedup + phase2)
									* width + center;
							var blu = Math.sin(frequency3 * speedup + phase3)
									* width + center;
							return [ red, grn, blu, a ];
						},
						makeColorByWindSpeedUp1 : function(windSpeed, topSpeed,
								maxSpeed, minSpeed, bottomSpeed, a) {
							if (topSpeed < maxSpeed)
								return;
							if (maxSpeed < minSpeed)
								return;

							var gstart = 62 * (1 - 0.1 / (minSpeed
									- bottomSpeed + 0.1));
							var rend = 138 - (138 - 87)
									* (1 - 0.1 / (topSpeed - maxSpeed + 0.1));
							var bend = 95 + (136 - 95)
									* (1 - 0.1 / (topSpeed - maxSpeed + 0.1));

							if (windSpeed < bottomSpeed) {
								return [ 0, 0, 255, a ];
							} else if (windSpeed > topSpeed) {
								return [ rend, 0, bend, a ];
							}

							var interval = (maxSpeed - minSpeed) / 6;

							var rcolor = 0;
							var gcolor = 0;
							var bcolor = 255;

							if (windSpeed < minSpeed) {
								gcolor = 62 * (1 - 0.1 / (windSpeed
										- bottomSpeed + 0.1));
							} else if (windSpeed < (minSpeed + interval)) {
								gcolor = gstart + (windSpeed - minSpeed)
										* (255 - gstart) / interval; // g~255	
							} else if (windSpeed < (minSpeed + 2 * interval)) {
								rcolor = (windSpeed - (minSpeed + interval))
										* 8 / interval;
								gcolor = 255
										- (windSpeed - (minSpeed + interval))
										* (255 - 176) / interval;
								bcolor = 255
										- (windSpeed - (minSpeed + interval))
										* (255 - 17) / interval;
							} else if (windSpeed < (minSpeed + 3 * interval)) {
								rcolor = 8
										+ (windSpeed - (minSpeed + 2 * interval))
										* (255 - 8) / interval;
								gcolor = 176
										+ (windSpeed - (minSpeed + 2 * interval))
										* (255 - 176) / interval;
								bcolor = 17
										- (windSpeed - (minSpeed + 2 * interval))
										* 17 / interval;
							} else if (windSpeed < (minSpeed + 4 * interval)) {
								rcolor = 255;
								gcolor = 255
										- (windSpeed - (minSpeed + 3 * interval))
										* (255 - 175) / interval;
								bcolor = 0;
							} else if (windSpeed < (minSpeed + 5 * interval)) {
								rcolor = 255;
								gcolor = 190
										- (windSpeed - (minSpeed + 4 * interval))
										* 175 / interval;
								bcolor = 0;
							} else if (windSpeed < maxSpeed) {
								rcolor = 255
										- (windSpeed - (minSpeed + 5 * interval))
										* (255 - 138) / interval;
							} else {
								rcolor = 138
										- (138 - 87)
										* (1 - 0.1 / (windSpeed - maxSpeed + 0.1));
								gcolor = 0;
								bcolor = 95
										+ (136 - 95)
										* (1 - 0.1 / (windSpeed - maxSpeed + 0.1));
							}
							return [ rcolor, gcolor, bcolor, a ];
						}
					},
					particles : {
						velocityScale : 1 / 60000,
						maxIntensity : 12
					}
				//例子s :{速度规模  最大强度}							
				});
			}
		}
		function productsFor(attributes) {
			var attr = _.clone(attributes);
			results = [];
			results.push(factory.create(attr));
			return results;
		}
		return {
			buildProduct : buildProduct,
			productsFor : productsFor
		}
	}();
	function boundsFuc(bounds){
		bounds.width = document.body.clientWidth;
		bounds.height = document.body.clientHeight;
	}
	function interpolateField(grids) {
		//if(!map || !grids) return null;
		var mask = tools.createMask();
		var primaryGrid = grids.primaryGrid;
		var overlayGrid = grids.overlayGrid;

		var d = when.defer();
		var cancel = this.cancel;
		
		//重新计算边界。
		//boundsFuc(windObj.bounds);
		//粒子在屏幕上的移动速度(考虑美学选择合适的值);
		//var velocityScale = bounds.height * primaryGrid.particles.velocityScale;

		var columns = [];
		var colorss = [];
		var point = [];
		var x = windObj.bounds.x;
		var interpolate = primaryGrid.interpolate;
		var overlayInterpolate = overlayGrid.interpolate;
		var hasDistinctOverlay = primaryGrid !== overlayGrid;
		var scale = overlayGrid.scale;

		function interpolateColumn(x) {
			var column = [];
			var colors = [];
			for (var y = windObj.bounds.y; y < windObj.bounds.yMax; y += 1) {
				if (mask.isVisible(x, y)) {
					var color = TRANSPARENT_BLACK;
					//这里已经算出风速了
					wind = interpolate(x, y);
					var scalar = null;
					if (wind) {
						//进阶，失真神马的
						//wind = distort(projection, λ, φ, x, y, velocityScale, wind);
						scalar = wind[2];
						//if(scalar>11){
						//	console.log(scalar);
						//}
					}
					//?
					//if(hasDistinctOverlay){
					//	scalar = overlayInterpolate(λ, φ);
					//}
					if (isValue(scalar)) {
						//color = scale.gradient(scalar, OVERLAY_ALPHA);
						//color = scale.makeColorByWindSpeedUp(redFrequency, grnFrequency, bluFrequency,phase1,phase2,phase3,128, 127, scalar, OVERLAY_ALPHA);
						color = scale.makeColorByWindSpeedUp1(scalar, topSpeed,
								maxSpeed, minSpeed, bottomSpeed, windObj.OVERLAY_ALPHA);
					}
					column[y + 1] = column[y] = wind || HOLE_VECTOR;
					colors[y + 1] = colors[y] = color;
					mask.set(x, y, color).set(x + 1, y, color).set(x, y + 1,
							color).set(x + 1, y + 1, color);
				}
			}
			columns[x + 1] = columns[x] = column;
			colorss[x + 1] = colorss[x] = colors;
		}

		(function batchInterpolate() {
			try {
				if (!cancel.requested) {
					var start = Date.now();
					while (x < windObj.bounds.xMax) {
						interpolateColumn(x);
						x += 1;
						if ((Date.now() - start) > MAX_TASK_TIME) {
							setTimeout(batchInterpolate, MIN_SLEEP_TIME);
							return;
						}
					}
				}
				//console.log(colorss);
				d.resolve(createField(columns, windObj.bounds, mask));
			} catch (e) {
				d.reject(e);
			}
		})();
		return d.promise;
	}
	function animate(field, grids) {
		if (!field || !grids)
			return;
		var cancel = this.cancel;
		//速度最快的粒子颜色强度是最大的，计算出每个级别风速的颜色
		var colorStyles = windIntensityColorScale(INTENSITY_SCALE_STEP,
				grids.primaryGrid.particles.maxIntensity);
		//?
		var buckets = colorStyles.map(function() {
			return [];
		});
		var particleCount = Math.round(windObj.bounds.xMax * PARTICLE_MULTIPLIER);
		var fadeFillStyle = 'rgba(0, 0, 0, 0.97)';
		var particles = [];
		for (var i = 0; i < particleCount; i++) {
			particles.push(field.randomize({
				age : _.random(0, MAX_PARTICLE_AGE)
			})); //随机生成点和点的生命
		}
		//粒子演化过程
		function evolve() {
			buckets.forEach(function(bucket) {
				bucket.length = 0
			});
			particles.forEach(function(particle) {
				if (particle.age > MAX_PARTICLE_AGE) {
					field.randomize(particle).age = 0;
				}
				var x = particle.x;
				var y = particle.y;
				var v = field(x, y); //在当前位置的矢量
				var m = v[2];
				if (m < windObj.speedupThresHold) {
					particle.alpha = true;
				} else {
					particle.alpha = false;
				}
				if (m === null) {
					particle.age = MAX_PARTICLE_AGE; //粒子逃离网格，就永远不会回来
				} else {
					var xt = x + v[0];
					var yt = y + v[1];
					if (field.isDefined(xt, yt)) {
						//路径从（x,y）到路径(xt,yt)是可见的，所以将这种例子添加到适当的画桶中
						particle.xt = xt;
						particle.yt = yt;
						buckets[colorStyles.indexFor(m)].push(particle);
					} else {
						//粒子不可见，仍然要移动到这里
						particle.x = xt;
						particle.y = yt;
					}
				}
				particle.age += 1;
			});
		}
		var g = d3.select("#" + grids.options.renderTo[0]).node().getContext(
				"2d");
		g.lineWidth = PARTICLE_LINE_WIDTH;
		g.fillStyle = fadeFillStyle;

		function draw() {
			//褪色存在例子的跟踪信息
			var prev = g.globalCompositeOperation;
			//在源图像中显示目标图像。只有源图像之内的目标图像部分会被显示，源图像是透明的。
			g.globalCompositeOperation = "destination-in";
			g.fillRect(windObj.bounds.x, windObj.bounds.y, windObj.bounds.xMax,
					windObj.bounds.yMax);
			g.globalCompositeOperation = prev;

			//绘制新的粒子痕迹
			buckets.forEach(function(bucket, i) {
				if (bucket.length > 0) {
					g.beginPath();
					var colorStyle = colorStyles[i];
					bucket.forEach(function(particle) {
						if (particle.alpha) {
							g.strokeStyle = 'rgba(0, 0, 0, 0)';
						} else {
							//colorStyle = 'rgba(180,235,124,1)';
							//colorStyle = 'rgba(30,30,30,0.6)';
							g.strokeStyle = colorStyle;
						}
						g.moveTo(particle.x, particle.y);
						g.lineTo(particle.xt, particle.yt);
						particle.x = particle.xt;
						particle.y = particle.yt;
					});
					g.stroke();
				}
			});
		}
		(function frame() {
			try {
				if (cancel.requested) {
					field.release();
					return;
				}
				evolve();
				draw();
				windObj.animateTimer = setTimeout(frame, FRAME_RATE);
			} catch (e) {
				console.log(e);
			}
		})();
	}
	function drawOverlay(field, gridAgent_, options) {
		if (!field)
			return;
		var ctx = d3.select('#' + options.renderTo[1]).node().getContext('2d');
		d3.select('#' + options.renderTo[1]).on(
				'mousemove',
				function(evt) {
					var evt = evt || window.event;
					var target = evt.target || evt.srcElement;
					if (target.nodeName.toLowerCase() == "canvas"
							&& target.className.toLowerCase() == "overlay") {
						var mousePosition = getMousePosition(target, evt);
						var x = mousePosition.x;
						var y = mousePosition.y;
						//获取风速
						var wind = field(x, y);
						d3.select('#' + options.renderTo[1]).attr(
								'title',
								'当前坐标点：x:' + x + ' , y:' + y + ', 风速:'
										+ wind[2] + 'm/s');
					}
				});
		tools.clearCanvas(d3.select('#' + options.renderTo[1]).node());
		tools.clearCanvas(d3.select("#" + options.renderTo[2]).node());
		ctx.putImageData(field.overlay, 0, 0);
		var grid = (gridAgent_.value() || {}).overlayGrid;
		if (grid) {
			// Draw color bar for reference.
			var colorBar = d3.select("#" + options.renderTo[2]);
			var scale = grid.scale;
			var bounds = scale.bounds;
			var c = colorBar.node();
			if (!c)
				return;
			var g = c.getContext("2d");
			var n = c.width - 1;
			for (var i = 0; i <= n; i++) {
				/**
				var rgb = scale.gradient(spread(i / n, bounds[0], bounds[1]), 1);
				 **/
				//var rgb = scale.makeColorByWindSpeedUp(redFrequency, grnFrequency, bluFrequency,phase1,phase2,phase3,128, 127, i/n*12,OVERLAY_ALPHA);
				var rgb = scale.makeColorByWindSpeedUp1(i / n * 12, topSpeed,
						maxSpeed, minSpeed, bottomSpeed, windObj.OVERLAY_ALPHA);
				g.fillStyle = "rgb(" + rgb[0].toFixed(0) + ","
						+ rgb[1].toFixed(0) + "," + rgb[2].toFixed(0) + ")";
				g.fillRect(i, 0, 1, c.height);
			}

			// Show tooltip on hover.
			colorBar.on("mousemove", function() {
				var x = d3.mouse(this)[0];
				var pct = clamp((Math.round(x) - 2) / (n - 2), 0, 1);
				var value = spread(pct, bounds[0], bounds[1]);
				var units = grid.units[0];
				colorBar.attr("title", formatScalar(value, units) + " "
						+ units.label);
			});
		}
	}

	var options = {
		param : 'wind',
		paths : [ './static/data/wind_88m_sector_0.json' ],
		renderTo : [ 'animation', 'overlay', 'scale', 'display' ]
	}

	windObj = new CreateWind(options);
	
	var draggingObj = null;
	var diffX = 0;
	var diffY = 0;
	function down(e) {
		if (e.target.className.indexOf('dialog-title') != -1) {
			draggingObj = e.target.offsetParent;
			diffX = event.clientX - draggingObj.offsetLeft;
			diffY = event.clientY - draggingObj.offsetTop;
		}
	}
	function move(e) {
		var dialog = document.getElementById('dlgTest');
		if (draggingObj) {//只有点击Dialog Title的时候才能拖动
			dialog.style.left = (e.clientX - diffX) + 'px';
			dialog.style.top = (e.clientY - diffY) + 'px';
		}
	}
	function up(e) {
		draggingObj = null;
		diffX = 0;
		diffY = 0;
	}
	document.addEventListener('mousedown', down);
	document.addEventListener('mousemove', move);
	document.addEventListener('mouseup', up);
	window.onload = function() {
		d3.select('#enableThreshold').on('change', function() {
			if (this.checked) {
				d3.select('#speedupThresHold').classed("hidden", false);
				windObj.setSpeedupThresHold(d3.select('#speedupThresHold').value);
			} else {
				d3.select('#speedupThresHold').classed("hidden", true);
				windObj.setSpeedupThresHold(0);
			}
		});
		d3.select('#speedupThresHold').on('change', function() {
			windObj.setSpeedupThresHold(this.value);
		});
		d3.select('#followedFrame').on('change', function() {
			if (this.checked) {
				d3.select('#dlgTest').style({
					'position' : 'fixed'
				});
			} else {
				d3.select('#dlgTest').style({
					'position' : 'absolute'
				});
			}
		});
	}
	function getMousePosition(canvas, evt) {
		var rect = canvas.getBoundingClientRect();
		return {
			x : evt.clientX - rect.left * (canvas.width / rect.width),
			y : evt.clientY - rect.top * (canvas.height / rect.height)
		};
	}
})();
